// This kernel fetches data from global memory to kernel and 
// then directly stores them back to global memory
// Different accessing patterns are compared to the influences on bandwidth
// 2015.06.17 by wangdong@bjtu.edu.cn
#define AP_INT_MAX_W 32768 // Must be defined before "ap_int.h"
#include "ap_int.h"
#include "ap_axi_sdata.h"
#include "hls_stream.h"

typedef unsigned int  uint;

#define VEC_SIZE    16

// coding style 1
typedef ap_uint<VEC_SIZE*32> float_vec;
 // coding style 2
//typedef struct {
//   float data[VEC_SIZE];
//} float_vec;

void dataLoad(
                const float_vec *A_in,
				const uint burst_num,
				const uint trans_num,
				hls::stream<float_vec> &data_stream
			)
{
#pragma HLS INLINE off
	float_vec tmp;

	for(uint i=0; i<trans_num; i++){
		for(uint j=0; j<burst_num; j++){
			tmp = A_in[i*burst_num+j];
			data_stream.write(tmp);
		}
	}

}

void dataStore(
                float_vec *B_out,
				const uint data_num,
				hls::stream<float_vec> &data_stream
			)
{
#pragma HLS INLINE off
	float_vec tmp;

	for(uint i=0; i<data_num; i++){
		tmp = data_stream.read();
		B_out[i] = tmp;
	}

}

extern "C" {
void memAccess(
                const float_vec *A_in,
                float_vec *B_out,
				const uint data_num, // total num of data
				const uint burst_num, // num of burst per trans
				const uint trans_num  // total num of transfer
				)
{
	hls::stream<float_vec> data_stream;
#pragma HLS STREAM variable = data_stream  depth = 256

#pragma HLS DATAFLOW
	dataLoad(A_in, burst_num, trans_num, data_stream);
	dataStore(B_out, data_num, data_stream);
}
}